package ext.tianma.bom.util;

import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import com.ptc.core.logging.Log;
import com.ptc.core.logging.LogFactory;
import com.ptc.netmarkets.workflow.NmWorkflowHelper;
import wt.fc.IteratedObjectVector;
import wt.fc.ObjectIdentifier;
import wt.fc.ObjectReference;
import wt.fc.Persistable;
import wt.fc.PersistenceHelper;
import wt.fc.PersistenceServerHelper;
import wt.fc.PersistentReference;
import wt.fc.QueryResult;
import wt.iba.definition.StringDefinition;
import wt.iba.definition.litedefinition.AttributeDefDefaultView;
import wt.iba.definition.litedefinition.StringDefView;
import wt.iba.definition.service.IBADefinitionHelper;
import wt.inf.container.WTContained;
import wt.inf.container.WTContainerHelper;
import wt.inf.container.WTContainerRef;
import wt.method.RemoteAccess;
import wt.method.RemoteMethodServer;
import wt.org.WTPrincipal;
import wt.query.ClassAttribute;
import wt.query.OrderBy;
import wt.query.QueryException;
import wt.query.QuerySpec;
import wt.query.SearchCondition;
import wt.query.SubSelectExpression;
import wt.query.TableColumn;
import wt.session.SessionContext;
import wt.session.SessionHelper;
import wt.session.SessionServerHelper;
import wt.util.WTException;
import wt.util.WTProperties;
import wt.vc.baseline.ManagedBaseline;
import wt.workflow.WfException;
import wt.workflow.definer.WfDefinerHelper;
import wt.workflow.definer.WfProcessDefinition;
import wt.workflow.engine.ProcessData;
import wt.workflow.engine.WfActivity;
import wt.workflow.engine.WfEngineHelper;
import wt.workflow.engine.WfProcess;
import wt.workflow.engine.WfRequesterActivity;
import wt.workflow.work.WfAssignedActivity;
import wt.workflow.work.WorkItem;
import wt.workflow.work.WorkflowHelper;

public class WfUtil implements RemoteAccess {

	private static Log log = LogFactory.getLog(WfUtil.class);

	public final static String BASELINEFOLDERNAME = "/Default/SYSMGT/BASELINE";

	private static long WORKFLOW_PRIORITY = 1;

	/**
	 * start a workflow
	 *
	 * @param workFlowName
	 * @param pbo
	 * @param attributes 流程变量
	 */
	public static WfProcess startWorkflow(String workflowName, Object pbo,
			Map attributes) {
		WfProcess wfprocess = null;
		try {
			if (!RemoteMethodServer.ServerFlag) {
				return (WfProcess)RemoteMethodServer.getDefault().invoke("startWorkflow",
						WfUtil.class.getName(), null,
						new Class[] { String.class, Object.class,Map.class },
						new Object[] { workflowName, pbo, attributes });
			}
				boolean enforce = wt.session.SessionServerHelper.manager
						.setAccessEnforced(false);
				try {
					WTContainerRef containerRef = null;
					try {
						containerRef = WTContainerHelper.service
								.getExchangeRef();
					} catch (WTException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}

					if (pbo instanceof WTContained) {
						WTContained contained = (WTContained) pbo;
						containerRef = contained.getContainerReference();
					}
					try {
						WTProperties wtproperties = WTProperties
								.getLocalProperties();
						WORKFLOW_PRIORITY = Long
								.parseLong(wtproperties
										.getProperty(
												"wt.lifecycle.defaultWfProcessPriority",
												"1"));

						WfProcessDefinition wfprocessdefinition = WfDefinerHelper.service
								.getProcessDefinition(workflowName,
										containerRef);
						if (wfprocessdefinition == null) {
							return wfprocess;
						}

						wfprocess = WfEngineHelper.service.createProcess(
								wfprocessdefinition, null, containerRef);

						ProcessData processdata = wfprocess.getContext();
						processdata.setValue("primaryBusinessObject", pbo);

						if (attributes != null && !attributes.isEmpty()) {
							Set attr = attributes.keySet();
							for (Iterator iter = attr.iterator(); iter
									.hasNext();) {
								String key = (String) iter.next();
								processdata.setValue(key, attributes.get(key));
							}
						}

						WfEngineHelper.service.startProcessImmediate(wfprocess,
								processdata, WORKFLOW_PRIORITY);

					} catch (Exception e) {
						e.printStackTrace();
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					SessionServerHelper.manager.setAccessEnforced(enforce);
				}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return wfprocess;
	}

	/**
	 * start a workflow without pbo
	 *
	 * @param workFlowName
	 * @param attributes 流程变量
	 */
	public static WfProcess startWorkflowWithoutPBO(String workflowName, Map attributes) throws WTException {
		WfProcess wfprocess = null;

	      WTPrincipal administrator = SessionHelper.manager.getAdministrator();
	      WTPrincipal previous = SessionContext.setEffectivePrincipal (administrator);
		try {
			if (!RemoteMethodServer.ServerFlag) {
				return (WfProcess)RemoteMethodServer.getDefault().invoke("startWorkflow",
						WfUtil.class.getName(), null,
						new Class[] { String.class, Object.class,Map.class },
						new Object[] { workflowName, attributes });
			}

			boolean enforce = wt.session.SessionServerHelper.manager
					.setAccessEnforced(false);
			try {
				String containerPath = "/wt.inf.container.OrgContainer=airchina/wt.inf.library.WTLibrary=AD";
				WTContainerRef containerRef = WTContainerHelper.service.getByPath(containerPath);
				log.info("get containerRef as ---------------> " + containerRef);
				try {
					WTProperties wtproperties = WTProperties
							.getLocalProperties();
					WORKFLOW_PRIORITY = Long.parseLong(wtproperties.getProperty("wt.lifecycle.defaultWfProcessPriority", "1"));

					WfProcessDefinition wfprocessdefinition = WfDefinerHelper.service
							.getProcessDefinition(workflowName,
									containerRef);
					log.info("get wfprocessdefinition as ---------------> " + wfprocessdefinition);
					if (wfprocessdefinition == null) {
						return wfprocess;
					}

					wfprocess = WfEngineHelper.service.createProcess(
							wfprocessdefinition, null, containerRef);
					log.info("get wfprocess as ---------------> " + wfprocess);

					ProcessData processdata = wfprocess.getContext();

					if (attributes != null && !attributes.isEmpty()) {
						Set attr = attributes.keySet();
						for (Iterator iter = attr.iterator(); iter.hasNext();) {
							String key = (String) iter.next();
							processdata.setValue(key, attributes.get(key));
						}
					}

					WfEngineHelper.service.startProcessImmediate(wfprocess,
							processdata, WORKFLOW_PRIORITY);

					log.info("process startup ---------------> " + wfprocess);

				} catch (Exception e) {
					e.printStackTrace();
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				SessionServerHelper.manager.setAccessEnforced(enforce);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}    finally {
	         SessionContext.setEffectivePrincipal (previous);
	      }
		return wfprocess;
	}


	/**
	 * complete the specific activity and set the variable to the given value
	 *
	 * @author xiaofzhang 2011-8-24
	 * @param process
	 * @param activityName
	 * @param varname
	 */
	public static boolean workComplete(WfProcess process, String activityName,
			String varname, Object obj) {
		try {
			Enumeration item = WfUtil.getWorkItems(process);
			if (!item.hasMoreElements()) {
				return false;
			}
			while (item.hasMoreElements()) {
				WorkItem wi = (WorkItem) item.nextElement();
				WfActivity wa = (WfActivity) wi.getSource().getObject();
				if (wa.getName().equals(activityName)) {
					if (varname != null) {
						wa.getContext().setValue(varname, obj);
					}
					wa = (WfActivity) PersistenceHelper.manager.modify(wa);
					Vector vector = new Vector();
					vector.add("");
					WorkflowHelper.service.workComplete(wi, wi.getOwnership()
							.getOwner(), vector);
				}
			}
		} catch (WTException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return true;
	}

	public static ManagedBaseline getBaseline(String baselinename) {
		ManagedBaseline baseline = null;

		try {
			QuerySpec qs = new QuerySpec(ManagedBaseline.class);
			SearchCondition sc = new SearchCondition(ManagedBaseline.class,
					ManagedBaseline.NAME, "=", baselinename);
			qs.appendWhere(sc);
			QueryResult qr = PersistenceHelper.manager.find(qs);
			if (qr.hasMoreElements()) {
				baseline = (ManagedBaseline) qr.nextElement();
			}
		} catch (Exception e) {
			log.debug("The Query for baseline has error: " + e.getMessage());
		}
		return baseline;
	}


	public static QueryResult getWorkItems(WfProcess wfprocess)
			throws Exception {

		QueryResult queryresult;
		QuerySpec queryspec = new QuerySpec();
		queryspec.setAdvancedQueryEnabled(true);
		int i = queryspec.appendClassList(WfAssignedActivity.class, false);
		queryspec.appendSelectAttribute(
				"thePersistInfo.theObjectIdentifier.id", i, false);
		queryspec.appendWhere(new SearchCondition(WfAssignedActivity.class,
				"parentProcessRef.key", "=", getOid(wfprocess)));
		SubSelectExpression subselectexpression = new SubSelectExpression(
				queryspec);
		QuerySpec queryspec1 = new QuerySpec(WorkItem.class);
		queryspec1.setAdvancedQueryEnabled(true);

		queryspec1.appendWhere(new SearchCondition(WorkItem.class, "completedBy", true), 0);
		ClassAttribute classattribute = new ClassAttribute(WorkItem.class,
				"source.key.id");
		queryspec1.appendAnd();
		SearchCondition searchcondition = new SearchCondition(classattribute,
				"IN", subselectexpression);

		Date data = new Date();
		queryspec1.appendWhere(searchcondition, 0);
		TableColumn ca = new TableColumn("A0", "createstampa2");
		OrderBy orderBy = new OrderBy(ca, false);
		queryspec1.appendOrderBy(orderBy, new int[0]);
		queryresult = PersistenceServerHelper.manager.query(queryspec1);

		return queryresult;

	}
	public static ObjectIdentifier getOid(Object obj) {
		if (obj == null)
			return null;
		if (obj instanceof ObjectReference)
			return (ObjectIdentifier) ((ObjectReference) obj).getKey();
		else
			return PersistenceHelper.getObjectIdentifier((Persistable) obj);
	}
	
	/**
	 * get Uncompleted WorkItems through pbo
	 *
	 * @author xiaofzhang 2011-8-24
	 * @param pbo
	 * @param activityName
	 * @return
	 * @throws WTException
	 */
	public static QueryResult getUncompletedWorkItems(Persistable pbo,
			String activityName) throws WTException {
		QuerySpec queryspec = new QuerySpec(WorkItem.class, WfActivity.class);
		queryspec.setSelect(1, false);
		SearchCondition searchconditionjoin = new SearchCondition(
				WorkItem.class, WorkItem.SOURCE + ".key.id", WfActivity.class,
				WfActivity.PERSIST_INFO + ".theObjectIdentifier.id");
		queryspec.appendWhere(searchconditionjoin, 0, 1);

		SearchCondition searchcondition = new SearchCondition(WorkItem.class,
				"primaryBusinessObject.key.classname", "=", PersistentReference
						.newPersistentReference(pbo).toString());
		queryspec.appendAnd();
		queryspec.appendWhere(searchcondition, 0);

		if (!StringUtils.isEmpty(activityName)) {
			SearchCondition searchcondition1 = new SearchCondition(
					WfActivity.class, "name", "=", activityName, true);
			queryspec.appendAnd();
			queryspec.appendWhere(searchcondition1, 1);
		}
		SearchCondition searchcondition2 = new SearchCondition(WorkItem.class,
				"completedBy", true);

		queryspec.appendAnd();
		queryspec.appendWhere(searchcondition2, 0);

		QueryResult queryresult = PersistenceHelper.manager.find(queryspec);

		return queryresult;
	}

	/**
	 * get uncompleted workitems through process
	 *
	 * @author xiaofzhang 2011-8-24
	 * @param process
	 * @param activityName
	 * @return
	 * @throws WTException
	 */
	public static QueryResult getUncompletedWorkItems(WfProcess process,
			String activityName) throws WTException {
		QueryResult queryresult = getUncompletedWorkItems((Persistable) process
				.getContext().getValue("primaryBusinessObject"), activityName);

		IteratedObjectVector iteratedobjectvector = new IteratedObjectVector();
		Vector vector = queryresult.getObjectVector().getVector();
		for (int i = 0; i < vector.size(); i++) {
			WorkItem workitem = (WorkItem) vector.elementAt(i);
			WfActivity wa = (WfActivity) workitem.getSource().getObject();
			if (isSubprocess(wa.getParentProcess(), process))
				iteratedobjectvector.addElement(workitem);
		}
		return new QueryResult(iteratedobjectvector);
	}

	/**
	 * check if this process is a child of the other process
	 *
	 * @author xiaofzhang 2011-8-24
	 * @param subProcess
	 * @param parProcess
	 * @return
	 */
	public static boolean isSubprocess(WfProcess subProcess,
			WfProcess parProcess) {
		if (subProcess.getIdentity().equals(parProcess.getIdentity()))
			return true;
		try {
			QuerySpec qs = new QuerySpec(WfRequesterActivity.class);
			SearchCondition searchcondition3 = new SearchCondition(
					WfRequesterActivity.class,
					WfRequesterActivity.PERFORMER_REF + ".key.id", "=",
					subProcess.getPersistInfo().getObjectIdentifier().getId());
			qs.appendWhere(searchcondition3, 0);
			QueryResult qr = PersistenceHelper.manager.find(qs);
			while (qr.hasMoreElements()) {
				WfRequesterActivity act = (WfRequesterActivity) qr
						.nextElement();
				if (act.getParentProcess().getIdentity()
						.equals(parProcess.getIdentity()))
					return true;
			}
		} catch (QueryException e) {
			e.printStackTrace();
		} catch (WTException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * @author 
	 * @param pbo
	 * @return
	 * @throws WfException
	 * @throws WTException
	 */
	public static WfProcess getProcessByPbo(Persistable pbo) throws WTException{
		QueryResult qr = NmWorkflowHelper.service.getAssociatedProcesses(pbo, null, null);
		WfProcess process = null;
		if(qr.hasMoreElements()){
			return (WfProcess) qr.nextElement();
		}
		return process;
	}

	//desmond
	public static StringDefinition getStringDefByPath(String ibaKey) {
		if (!RemoteMethodServer.ServerFlag) {
			try {
				return (StringDefinition) RemoteMethodServer.getDefault().invoke("getStringDefByPath", WfUtil.class.getName(), null,
						new Class[] { String.class }, new Object[] { ibaKey });
			} catch (Exception e) {
				log.error(ExceptionUtils.getStackTrace(e));
			}
		}
		StringDefinition stringDef = null;
		try {
			AttributeDefDefaultView defView = IBADefinitionHelper.service.getAttributeDefDefaultViewByPath(ibaKey);
			if (defView instanceof StringDefView) {
				stringDef = (StringDefinition) ObjectReference.newObjectReference(((StringDefView) defView).getObjectID()).getObject();
			}
		} catch (Exception e) {
			log.error("Get IBA Definition [" + ibaKey + "] Error: " + ExceptionUtils.getStackTrace(e));
		}
		return stringDef;
	}

}